/***************************************************************
*Defines for the lines used to communicate with the TTS module
*are listed below. There are data direction (TRIS) settings
*under spi_setup that need to be changed if these are moved.
****************************************************************/
 
#define TTS_RESET PORTCbits.RC0    // connects to X5-1
#define TTS_MISO PORTCbits.RC4        // connects to X5-2
#define TTS_notSS PORTCbits.RC1    // connects to X5-3
#define TTS_SCLK PORTCbits.RC3        // connects to X5-4
#define TTS_RnotB PORTCbits.RC2    // connects to X5-5
#define TTS_MOSI PORTCbits.RC5        // connects to X5-6
#define TTS_INT PORTCbits.RC6        // connects to X5-7
 
#include <p18f452.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <delay.h>
 
//Function prototypes
void tts_setup (void);
void spi_setup(void);
void tts_reset(void);
char SPI_comm(char sendChar);
void tts_send_command(char* command, char* output);
void tts_send_string(char* command, char* output);
void get_weight_line(int weight, char* unit, char* output);
void tts_wait(void);
void speak(char* outstring);
char tts_is_ready(void);
 
 
//Strings
 
static unsigned char _status[] = {0x04,0x00,0xFF}; // Request Status command.
static unsigned char _status_long[] = {0x04,0x00,0x00,0x00,0xFF}; // Request long Status.
static unsigned char _set_clock[] = {0x14,0x00,0xFF}; // Set Clock command.
static unsigned char _power_up[] = {0x02,0x00,0xFF}; // PowerUp command.
static unsigned char _set_vol[] = {0x51,0x00,0xFF}; // Set volume register at maximum command.
static unsigned char _set_int[] = {0x4E,0x20,0xFF}; // Enable conversion interrup command.
static unsigned char _clr_int[] = {0x06,0x00,0x00,0x00,0xFF}; // Clear interrupt flags command.
 
static unsigned char _data[] = "Welcome to Cassia Scales."; // Welcome Message.
static unsigned char _stop[] = {0x4B,0x00,0xFF}; // Stop conversion command.
 
 
/**
 * A public array to store a string for the TTS unit.
 */
static unsigned char _say_str[64];
 
/**
 * A public array to store responses from the TTS unit.
 */
static unsigned char outbuff[64];
 
 
 
/**
 *Initialises the master-side hardware for SPI communication with the TTS unit.
 *@see tts_setup()
 */
void spi_setup(void)
{
    TRISCbits.TRISC5 = 0;    //SDO is output
    TRISCbits.TRISC3 = 0;    //SCK is output
    TRISCbits.TRISC4 = 1;    //SDO is input
    TRISCbits.TRISC1 = 0;    //RC1 (notSS) is output
    TRISCbits.TRISC0 = 0;    //RC0 (Reset) is output
    TRISCbits.TRISC2 = 1;    //RC0 (RnotB) is input
//    TRISCbits.TRISC6 = 1;    //RC1 (Interrupt) is input (NO LONGER USED)
 
 
    SSPCON1bits.CKP = 1;    //clock idle is high.
    SSPSTATbits.CKE = 1;
 
    SSPCON1bits.SSPM3 = 0;    //Set clock speed as
    SSPCON1bits.SSPM2 = 0;    //Fosc/64
    SSPCON1bits.SSPM1 = 1;    //
    SSPCON1bits.SSPM0 = 0;    //
 
    SSPSTATbits.SMP = 1;    // Sample at end of data output.
 
    SSPCON1bits.SSPEN = 1;    // Enable SPI
}
 
/**
 *Initialises the slave-side TTS unit.
 *@see spi_setup()
 */
void tts_setup (void)
{
    tts_reset();
 
    tts_send_command(_status,outbuff);
    if ((outbuff[0]==0x00)&&(outbuff[1]==0x80))
    {
        tts_send_command(_set_clock,outbuff);    // send set clock command.
        tts_send_command(_status,outbuff);    // send status request command.
        tts_send_command(_power_up,outbuff);    // send powerup command.
 
        tts_wait();                // wait for powerup.
 
        tts_send_command(_status,outbuff);    // send status request command.
    }
 
    if ((outbuff[0]==0x04)&&(outbuff[1]==0x80))
    {
        tts_reset();    // If TTS chip has status 0x0480, reset will bring it into
                // ready status 0x0580.
    }
 
    while (!((outbuff[0]==0x05)&&(outbuff[1]==0x80)))
    {
        tts_reset();
        tts_send_command(_status,outbuff);
    }
 
    if ((outbuff[0]&0x04)&&(outbuff[1]==0x80))
    {
        tts_send_command(_set_vol,outbuff);    // send volume command.
        tts_wait();
    }
 
    tts_send_command(_status_long,outbuff);
    while (outbuff[2]|outbuff[3])
    {
                            // waiting for converion buffer to
        tts_send_command(_status_long,outbuff); // be empty.
    }
 
    tts_send_command(_set_int,outbuff);        // Sending enable conversion completed
                            // interrupts.
    tts_send_command(_clr_int,outbuff);        // Clearing interrupt flags.
    tts_send_string(_data,outbuff);            // Sending welcome message.
 
}
 
/**
 *Generates a text string in the format "%d %s",weight,unit eg. "346 grams"
 *@param weight an integer weight
 *@param unit a pointer to a string containing the name of the desired unit.
 *@param output a pointer to an output string.
 */
void get_weight_line(int weight, char* unit, char* output)
{
    char count = 0;
    itoa(weight,output);        // Converts weight to a null terminated string.
 
    while(output[count])        // Finds the end of the weight string.
        count++;
 
    output[count]=' ';        // Replaces the \0 character with a space.
    count++;
 
    strcpy(&output[count],unit);    // Appends the units string to the weight string.
}
 
/**
 *Calls a delay function.
 */
void tts_wait(void)
{
    Delay1KTCYx(10);
}
 
/**
 *Resets the TTS module by setting the RESET line for longer than 0.5 micro seconds.
 */
void tts_reset(void)
{
 
    TTS_RESET = 1;
    tts_wait();
    TTS_RESET = 0;
}
 
/**
 *Sends a command to the TTS chip over the SPI communications module.
 *The SS' line is pulled low before the transmission and then raised
 *after the transmission is complete.
 *Commands passed to this function must be terminated with a '0xFF' character
 *as 0x00 is a frequently used opcode character for the TTS chip.
 *@param command a pointer to a string containing the command to be sent.
 *@param output a pointer to a buffer to hold the recieved output.
 *@see tts_send_string()
 */
void tts_send_command(char* command, char* output)
{
    char count = 0;
    TTS_notSS = 0;            //START TRANSMISSION
    while (command[count]!=0xFF) //Send the command string until 0xFF
    {
        output[count] = SPI_comm(command[count]);
        count++;
    }
    TTS_notSS = 1;            //END TRANSMISSION
    output[count] = 0xFF;    //Place 0xFF at the end of the recieve buffer
                            //for debugging.
}
/**
 *Sends a string to be spoken to the TTS chip over the SPI communications module.
 *The SS' line is pulled low before the transmission and then raised
 *after the transmission is complete.
 *The function prefixes the string with the 'convert' command - 0x8100 and
 *appends it with the termination character 0x1a.
 *@param command a pointer to a null terminated string to be spoken.
 *@param output a pointer to a buffer to hold the recieved output.
 *@see tts_send_command()
 */
void tts_send_string(char* command, char* output)
{
    char count = 0;
    TTS_notSS = 0;            //START TRANSMISSION
    output[0] = SPI_comm(0x81); // Send conversion command.
    output[1] = SPI_comm(0x00);
    while (command[count]!=0x00) // Send string until 0x00.
    {
        output[count+2] = SPI_comm(command[count]);
        count++;
    }
    output[count] = SPI_comm(0x1a); // Send termination character.
    TTS_notSS = 1;            //END TRANSMISSION
    output[count] = 0xFF;    //Place 0xFF at the end of the recieve buffer
                            //for debugging.
}
 
/**
 *Performs 1 complete 8-bit SPI transaction by sending one character
 *and receiving one character.
 *A timeout counter is implemented that resets the TTS module if the
 *R/B' line is not active within reasonable time.
 *@param sendChar a character to be transmitted
 *@return feedback character recieved from SPI communication.
 *@see tts_send_command(),tts_send_string()
 */
char SPI_comm(char sendChar)
{
    int counter = 0;
     while(!TTS_RnotB)        // Test the Ready/notBusy line.
    {
        counter++;            // Increment the timeout counter.
        if(counter == 0)
        {
            tts_reset();    // If timeout counter overflows,
            return 0;        // reset the TTS unit and exit.
        }
    }
    SSPBUF = sendChar;        // Write the character to the SPI buffer.
    while (!SSPSTATbits.BF)
    {
        //wait until reception is complete.
    }
    return SSPBUF;            // Read feedback character from SPI buffer.
 
}
/**
 *A public wrapper function to simplify speech functionality.
 *Clears any interrupt flags, stops any active conversions
 *and then transmits the desired string to the TTS chip.
 *@param outstring an ASCII string to be spoken.
 *@see tts_is_ready()
 */
void speak (char* outstring)
{
    tts_send_command(_clr_int,outbuff); // Clear interrupt flags.
    tts_send_command(_stop,outbuff);    // Stop active conversion.
    tts_send_string(outstring, outbuff);// Send new string.
}
 
/**
 *Checks the status bits received from the tts unit to see if
 *the 'conversion complete' flag has been set.
 *@return logical status of the ICNV status bit.
 */
char tts_is_ready(void)
{
    tts_send_command(_status,outbuff);    // Request a status.
    if (outbuff[0]&0x20)                // Check ICNV status bit.
        return 1;
    else
        return 0;
}